#include "cachePage.h"
//#include <unistd.h>
#include "cacheCommon.h"
#include "cacheObjectPool.h"

void* PageCache::systemAllocPage(size_t pagesize)
{
    return systemAlloc(pagesize);
}

void PageCache::systemFreePage(void* ptr, size_t pagesize)
{
    systemFree(ptr, pagesize);
}

qSpan* PageCache::getSpan(size_t pagenum)
{
    if(pagenum >= PAGE_NUM)
    {
        size_t size = pagenum << PAGE_SHIFT;
        void* ptr = systemAllocPage(size);
        if(!ptr)
            return nullptr;
        
        qSpan* sp = span_allocator_.New();
        if(!sp)
        {
            systemFree(ptr, size);
            return nullptr;
        }

        sp->pageid_ = reinterpret_cast<uintptr_t>(ptr) >> PAGE_SHIFT;
        sp->pagenum_ = pagenum;

        pagemap_.set(sp->pageid_ , sp);
        return sp;
    }


    std::lock_guard<std::recursive_mutex> lc(res_mt_);
    if(!page_spanlist_[pagenum].empty())
    {
        qSpan* sp = page_spanlist_[pagenum].popFront();
        return sp;
    }

    size_t count = PAGE_NUM;
    while(count--)
    {
        //向大的页去查找，然后进行切割
        for(int i = pagenum + 1; i < PAGE_NUM; ++i)
        {
            if(!page_spanlist_[i].empty())
            {
                qSpan* sp = page_spanlist_[i].popFront();

                //尾切
                sp->pagenum_ -= pagenum;
                
                qSpan* newsp = span_allocator_.New();
                newsp->pageid_ = sp->pageid_ + sp->pagenum_;
                newsp->pagenum_ = pagenum;
                //更新映射
                for(size_t j = 0; j < pagenum; ++j)
                {
                    pagemap_.set(newsp->pageid_ + j, newsp);
                }
                page_spanlist_[sp->pagenum_].pushFront(sp);

                return newsp;
            }
        }

        //没有申请最大页数128,页，再进行切割
        size_t pagesize = (PAGE_NUM - 1) << PAGE_SHIFT;
        void* ptr = systemAllocPage(pagesize);
        size_t pageid = reinterpret_cast<uintptr_t>(ptr) >> PAGE_SHIFT;
        if(pagemap_.ensure(pageid, PAGE_NUM - 1))
        {
            qSpan* sp = span_allocator_.New();
            sp->pageid_ = pageid;
            sp->pagenum_ = PAGE_NUM - 1;

            for(size_t i = 0; i < sp->pagenum_; ++i)
            {
                pagemap_.set(pageid + i, sp);
            }

            page_spanlist_[ sp->pagenum_].pushFront(sp);
        }
    }
}

qSpan* PageCache::getSpanByPageid(void* start)
{
    size_t pageid = reinterpret_cast<uintptr_t>(start) >> PAGE_SHIFT;
    return reinterpret_cast<qSpan*>(pagemap_.get(pageid));
}

void PageCache::releaseSpan(qSpan* sp)
{
    if(sp->pagenum_ >= PAGE_NUM)
    {
        //返还给系统
        systemFreePage(sp->list_, sp->pagenum_ << PAGE_SHIFT);
        span_allocator_.Delete(sp);
        pagemap_.set(sp->pageid_ , nullptr);

        return;
    }

    std::lock_guard<std::recursive_mutex> lc(res_mt_);
    //通过pagemap_找前/后span合并
	//合并只需要秀修改pageid和pagenum
	//找前面的合并，需要修改pageid和pagenum
	//找后面的合并需要修改pagenum，pageid就是当前span的
	//注意修改映射关系
    size_t tmppageid= sp->pageid_;
    while(true)
    {
        size_t pageid = sp->pageid_ + sp->pagenum_;
        qSpan* nsp = reinterpret_cast<qSpan*>(pagemap_.get(pageid));
        if(nsp == nullptr)
            break;

        if(sp == nsp)
            continue;
        
        if(nsp->usenum_ != 0)
            break;
        //合并大于最大页数，不进行合并
		if (nsp->pagenum_ + sp->pagenum_ >= PAGE_NUM)
            break;

        page_spanlist_[nsp->pagenum_].erase(nsp);
        sp->pagenum_ += nsp->pagenum_;


        //更新映射
        for(size_t i = 0; i < nsp->pagenum_; ++i)
        {
            pagemap_.set(nsp->pageid_ + i, sp);
        }

        std::cout << "合并span" << std::endl;
        span_allocator_.Delete(nsp);
    }

    while(true)
    {
        size_t pageid = sp->pageid_ - 1;
        qSpan* psp = reinterpret_cast<qSpan*>(pagemap_.get(pageid));
        if(psp == nullptr)
            break;

        if(sp == psp)
            continue;

        if(psp->usenum_ != 0)
            break;
        //合并大于最大页数，不进行合并
		if (psp->pagenum_ + sp->pagenum_ >= PAGE_NUM)
            break;
        
        page_spanlist_[psp->pagenum_].erase(psp);
        
        sp->pageid_ = psp->pageid_;
        sp->pagenum_ += psp->pagenum_;

        for(size_t i = 0; i < psp->pagenum_; ++i)
        {
            pagemap_.set(psp->pageid_ + i, sp);
        }

		std::cout << "合并span" << std::endl;
		span_allocator_.Delete(psp);
    }

    std::cout << "合并span" << std::endl;
    page_spanlist_[sp->pagenum_].pushFront(sp);
}

// void* PageCache::systemAllocBigPage(size_t size)
// {
//     return systemAlloc(size);
// }

// void PageCache::systemFreeBigPage(void* ptr, size_t size)
// {
//     systemFreeBig(ptr, size);
// }